﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Xml.Linq;
using Amib.Threading;
using HPPNet;
using System.Timers;
using HPPUtil;
using HPPUtil.Helpers;

namespace HPPClientLibrary.DownLoad
{
    [Serializable]
    public class DownloadManager : PropertyChangedBase
    {

        #region Fields
        private readonly Dictionary<string, JobInfo> _hashJobInfoDict;
        private int _totalThreadCount;
        private double _totalDownloadSpeed;

        private readonly SmartThreadPool _downloadThreadPool;
        private readonly SmartThreadPool _otherWorkThreadPool;
        private IClient _client;//

        private BufferPool _bufferPool;
        private readonly Timer _timerClock = new Timer();
        private long _timerCount;
        private Dictionary<string, TimerJob> _timerJobList;//<hash,timerJob>



        #endregion

        #region Properties

        public Dictionary<string, TimerJob> TimerJobList
        {
            get { return _timerJobList; }
            set { _timerJobList = value; }
        }

        public virtual Dictionary<string, JobInfo> HashJobInfoDict
        {
            get { return _hashJobInfoDict; }
        }

        public SmartThreadPool DownloadThreadPool
        {
            get { return _downloadThreadPool; }

        }
        public SmartThreadPool OtherWorkThreadPool
        {
            get { return _otherWorkThreadPool; }
        }

        public IClient Client
        {
            get { return _client; }
            set { _client = value; }
        }

        public BufferPool BufferPool
        {
            get { return _bufferPool; }
            set { _bufferPool = value; }
        }

        public List<DownMsg> DownloadInfos
        {
            get
            {
                List<DownMsg> downMsgs = new List<DownMsg>();
                foreach (KeyValuePair<string, JobInfo> info in HashJobInfoDict)
                {
                    JobInfo jobInfo = info.Value;
                    DownMsg msg = new DownMsg();
                    msg.Hash = jobInfo.Hash;
                    msg.FileLen = jobInfo.FileLen;
                    msg.FileName = jobInfo.FileName;
                    msg.Percent = jobInfo.LocalFileBlocks.Percent;
                    msg.Speed = jobInfo.DownloadJob == null ? -1 : jobInfo.DownloadJob.DownloadSpeed;
                    downMsgs.Add(msg);
                }

                return downMsgs;
            }
        }

        #endregion

        #region Methods

        public DownloadManager()
            : this(new HPPClient(), new Dictionary<string, JobInfo>()) // 2009.09.19 vls, create parameterless constructor for mock
        {

        }

        public DownloadManager(IClient client, Dictionary<string, JobInfo> hashJobInfoDict)
        {
            _hashJobInfoDict = hashJobInfoDict;
            _downloadThreadPool = new SmartThreadPool(client.Config.SmartThreadPoolTimeOut);
            _otherWorkThreadPool = new SmartThreadPool();
            _client = client;
            _bufferPool = new BufferPool(client.Config.TotalBufferSize / BasicSetting.BlockSize);
            _timerJobList = new Dictionary<string, TimerJob>();
            _timerClock.Interval = ConfigManager.DownloadManagerTimerInterval;
            _timerClock.Elapsed += new ElapsedEventHandler(OnTimer);
            _timerClock.Enabled = true;
            _timerCount = 0;
            _timerClock.Start();
        }

        public void OnTimer(Object source, ElapsedEventArgs e)
        {
            
            if (_timerJobList != null)
            {
                lock (_timerJobList)
                {
                    foreach (KeyValuePair<string, TimerJob> timerJob in _timerJobList)
                    {
                        if (_hashJobInfoDict.ContainsKey(timerJob.Key) && _hashJobInfoDict[timerJob.Key].Status == JobStatus.Downloading)
                        {
                            if (timerJob.Value.IsGetPeerListOnTime(ConfigManager.DownloadManagerTimerInterval, _client.Config.GetPeerListInterval))
                            {
                                if (_client.Config.ServerIP != null)
                                {
                                    CommonLogger.Logger.DebugFormat("OnTimer() QueueWorkItem(GetPeerList())");
                                    _otherWorkThreadPool.QueueWorkItem(new Action<IPEndPoint>(timerJob.Value.GetPeerList),
                                                                       _client.Config.ServerIP);
                                }
                            }
                            if (timerJob.Value.IsClearDisableIPListOnTime(ConfigManager.DownloadManagerTimerInterval, _client.Config.ClearDisableIpListInterval))
                            {
                                CommonLogger.Logger.DebugFormat("OnTimer() QueueWorkItem(ClearDisableIPList())");
                                _otherWorkThreadPool.QueueWorkItem(new Action(timerJob.Value.ClearDisableIPList));
                            }
                        }
                    }
                }

            }
        }



        public bool PauseJobs(List<string> hashList)
        {
            foreach (string hash in hashList)
            {
                PauseJob(hash);
            }
            return true;
        }

        public bool PauseJob(string hash)
        {
            if (_hashJobInfoDict.ContainsKey(hash) && _hashJobInfoDict[hash].Status == JobStatus.Downloading)
            {
                _hashJobInfoDict[hash].Pause();
                this.NotifyPropertyChanged(c => c.DownloadInfos);
            }

            return true;
        }

        public bool ContinueJob(string hash)
        {
            if (_hashJobInfoDict.ContainsKey(hash) && _hashJobInfoDict[hash].Status == JobStatus.Waiting)
            {
                _hashJobInfoDict[hash].Resum();
                this.NotifyPropertyChanged(c => c.DownloadInfos);

            }
            return true;
        }

        public bool ContinueJobs(List<string> hashList)
        {
            foreach (string hash in hashList)
            {
                ContinueJob(hash);
            }
            return true;
        }

        public bool StartDownload(string hash)
        {
            if (_hashJobInfoDict.ContainsKey(hash) && _hashJobInfoDict[hash].Status == JobStatus.Init)
            {
                DownloadJob downloadJob = new DownloadJob(_hashJobInfoDict[hash]);
                if (_hashJobInfoDict[hash].Start() == true)
                {
                    _hashJobInfoDict[hash].Status = JobStatus.Downloading;
                    this.NotifyPropertyChanged(c => c.DownloadInfos);
                    return true;
                }

            }
            return false;
        }



        /// <summary>
        /// 下载的总入口
        /// </summary>
        /// <param name="hash">要下载的hash</param>
        /// <param name="fileName">下载的文件名</param>
        /// <param name="isStartNow">是否立即开始下载的标志</param>
        /// <param name="path">下载路径</param>
        public NewJobReturnFlag Download(string hash, string path, string fileName, bool isStartNow)
        {
            if (_hashJobInfoDict.ContainsKey(hash))//新建的任务已经在下载列表中
            {
                return NewJobReturnFlag.AlreadyInJobList;
            }
            JobInfo newJob = new JobInfo(this, fileName);
            newJob.LocalFilePath = path;
            newJob.Hash = hash;
            newJob.Status = JobStatus.Init;

            _hashJobInfoDict.Add(hash, newJob);
            if (isStartNow == true)
            {
                StartDownload(hash);
            }
            return NewJobReturnFlag.Success;
        }
        #endregion
    }
}